/* Commonly used headers and some of Steven's, et. al. defined functions */
#ifndef __4335_6225_H_
#define __4335_6225_H_
#include	<sys/types.h>	/* basic system data types */
#include	<sys/socket.h>	/* basic socket definitions */
#include	<sys/time.h>	/* timeval{} for select() */
#include	<time.h>		/* timespec{} for pselect() */
#include	<netinet/in.h>	/* sockaddr_in{} and other Internet defns */
#include	<arpa/inet.h>	/* inet(3) functions */
#include	<errno.h>
#include	<fcntl.h>		/* for nonblocking */
#include	<netdb.h>
#include	<signal.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<sys/stat.h>	/* for S_xxx file mode constants */
#include	<sys/uio.h>		/* for iovec{} and readv/writev */
#include	<unistd.h>
#include	<sys/wait.h>
#include	<sys/un.h>		/* for Unix domain sockets */

#define	SA	struct sockaddr

#define MAXLINE 100 /* Students - YOU MAY CHANGE THIS VALUE */
static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];




/* Begin readline */
static ssize_t my_read(int fd, char *ptr)
{

    if (read_cnt <= 0) {
again:
	if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
	    if (errno == EINTR)
		goto again;
	    return(-1);
	} else if (read_cnt == 0)
	    return(0);
	read_ptr = read_buf;
    }

    read_cnt--;
    *ptr = *read_ptr++;
    return(1);
}

ssize_t readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t	n, rc;
    char	c, *ptr;

    ptr = vptr;
    for (n = 1; n < maxlen; n++) {
	if ( (rc = my_read(fd, &c)) == 1) {
	    *ptr++ = c;
	    if (c == '\n')
		break;	/* newline is stored, like fgets() */
	} else if (rc == 0) {
	    *ptr = 0;
	    return(n - 1);	/* EOF, n - 1 bytes were read */
	} else
	    return(-1);		/* error, errno set by read() */
    }

    *ptr = 0;	/* null terminate like fgets() */
    return(n);
}

ssize_t readlinebuf(void **vptrptr)
{
    if (read_cnt)
	*vptrptr = read_ptr;
    return(read_cnt);
}
/* end readline */


/* Begin readn */
/* Read "n" bytes from a descriptor. */
ssize_t readn(int fd, void *vptr, size_t n)
{
    size_t	nleft;
    ssize_t	nread;
    char	*ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
	if ( (nread = read(fd, ptr, nleft)) < 0) {
	    if (errno == EINTR)
		nread = 0;		/* and call read() again */
	    else
		return(-1);
	} else if (nread == 0)
	    break;				/* EOF */

	nleft -= nread;
	ptr   += nread;
    }
    return(n - nleft);		/* return >= 0 */
}
/* end readn */

/* Begin writen */
/* Write "n" bytes to a descriptor. */
ssize_t writen(int fd, const void *vptr, size_t n)
{
    size_t		nleft;
    ssize_t		nwritten;
    const char	*ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
	if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
	    if (nwritten < 0 && errno == EINTR)
		nwritten = 0;		/* and call write() again */
	    else
		return(-1);			/* error */
	}

	nleft -= nwritten;
	ptr   += nwritten;
    }
    return(n);
}
/* end writen */



/*****************    Wrapper Functions  ***********************/
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int	n;

    if ( (n = accept(fd, sa, salenptr)) < 0) {
	err_sys("accept error");
    }
    return(n);
}

void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (bind(fd, sa, salen) < 0)
	err_sys("bind error");
}

void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (connect(fd, sa, salen) < 0)
	err_sys("connect error");
}

void Listen(int fd, int backlog)
{
    if (listen(fd, backlog) < 0)
	err_sys("listen error");
}

int Socket(int family, int type, int protocol)
{
    int	n;

    if ( (n = socket(family, type, protocol)) < 0)
	err_sys("socket error");
    return(n);
}

int err_sys(const char *mssg)
{
    printf ("%s",mssg);
    exit(1);
}


void Writen(int fd, void *ptr, size_t nbytes)
{
    if (writen(fd, ptr, nbytes) != nbytes)
	err_sys("writen error");
}


ssize_t Readn(int fd, void *ptr, size_t nbytes)
{
    ssize_t		n;

    if ( (n = readn(fd, ptr, nbytes)) < 0)
	err_sys("readn error");
    return(n);
}

ssize_t Readline(int fd, void *ptr, size_t maxlen)
{
    ssize_t n;

    if ( (n = readline(fd, ptr, maxlen)) < 0)
	err_sys("readline error");
    return(n);
}

void Close(int fd)
{
    if (close(fd) == -1)
	err_sys("close error");
}

pid_t Fork(void)
{
    pid_t	pid;

    if ( (pid = fork()) == -1)
	err_sys("fork error");
    return(pid);
}

#endif

